#include "SJF_Scheduler.h"
#include <iostream>
#include <vector>

using namespace std;

SJF_Scheduler::SJF_Scheduler()
{
}

SJF_Scheduler::~SJF_Scheduler()
{
}

void SJF_Scheduler::sortProcesses()
{
	vector<Process>::iterator end, positionOne, positionTwo;
	bool swapped = true;

	end = processList.end();

	do
	{
		swapped = false;
		positionTwo = ++processList.begin();
		for(positionOne = processList.begin(); positionTwo != end; positionOne++, positionTwo++)
		{
			if(compareArrivalTime(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SJF_Scheduler::compareArrivalTime(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getArrivalTIme() > (*positionTwo).getArrivalTIme();
}

void SJF_Scheduler::runScheduler()
{
	vector<Process>::iterator index, processListItr, end;
	vector<Process> available_queue;
	Process temp(0,0,0);
	int endTimeOfPreviousProcess = 0;



	sortProcesses();

	processListItr = processList.begin();

	do
	{
		if(processListItr != processList.end())
		{
			if(processListItr == processList.begin())
				getQueuedProcesses(available_queue, processListItr, (*processListItr).getArrivalTIme() + (*processListItr).getCPU_Burst());
			else
				getQueuedProcesses(available_queue, processListItr, endTimeOfPreviousProcess + (*index).getCPU_Burst());
		}

		index = available_queue.begin();
		end = available_queue.end();

		
		//process came in after the previous job ended
		if((*index).getArrivalTIme() > endTimeOfPreviousProcess)
		{
			(*index).setStartTime((*index).getArrivalTIme());
			(*index).setEndTime((*index).getStartTime() + (*index).getCPU_Burst());
			endTimeOfPreviousProcess = (*index).getEndTime();
			
		}
		else //process came in prior to the previous job ending
		{
			
			vector<Process>::iterator firstProcess = processList.begin();
			findProcessID(firstProcess, (*index).getProcessID());

			//very first process in the processList
			if(firstProcess == processList.begin())
			{
				(*index).setStartTime((*index).getArrivalTIme());
				(*index).setEndTime((*index).getStartTime() + (*index).getCPU_Burst());
			}
			else
			{
				(*index).setStartTime(endTimeOfPreviousProcess);
				(*index).setEndTime((*index).getStartTime() + (*index).getCPU_Burst());
				
			}
			endTimeOfPreviousProcess = (*index).getEndTime();
		}
		


		temp = (available_queue.front());
		assignValuesToProcessList(temp);
		
		available_queue.erase(index);
		index = available_queue.begin();
		end = available_queue.end();
		
		if(available_queue.size() != 0)
			sortQueueByTime(available_queue);		

	}while(available_queue.size() != 0);
	

}

void SJF_Scheduler::getQueuedProcesses(vector<Process> &available_queue, vector<Process>::iterator &processListItr, int prevProcEndTime)
{
	int endTime = prevProcEndTime;
	int arrivalTime = 0;

	vector<Process>::iterator posOne, posTwo;	
	
	endTime = prevProcEndTime;
	arrivalTime = (*processListItr).getArrivalTIme();

	while(processListItr != processList.end() && arrivalTime <= endTime)
	{		
		if(arrivalTime <= endTime && !(*processListItr).isFinished())
			available_queue.push_back(*processListItr);
	
		processListItr++;

		if(processListItr != processList.end())
			arrivalTime = (*processListItr).getArrivalTIme();
	}
}

void SJF_Scheduler::assignValuesToProcessList(Process temp)
{
	vector<Process>::iterator location;
	location = processList.begin();
	findProcessID(location, temp.getProcessID());

	(*location).setEndTime(temp.getEndTime());
	(*location).setStartTime(temp.getStartTime());
	(*location).setFinished();

}

void SJF_Scheduler::findProcessID(vector<Process>::iterator &location, int processID)
{
	while((*location).getProcessID() != processID)
		location++;
}

void SJF_Scheduler::sortQueueByTime(std::vector<Process> &queue)
{
	vector<Process>::iterator end, positionOne, positionTwo;
	bool swapped = true;

	end = queue.end();

	do
	{
		swapped = false;
		positionTwo = ++queue.begin();
		for(positionOne = queue.begin(); positionTwo != end; positionOne++, positionTwo++)
		{
			if(compareCPU_Burst(positionOne, positionTwo))
			{
				swap(*positionOne, *positionTwo);
				swapped = true;
			}
		}
	}while(swapped);
}

bool SJF_Scheduler::compareCPU_Burst(vector<Process>::iterator positionOne, vector<Process>::iterator positionTwo)
{
	return (*positionOne).getCPU_Burst() > (*positionTwo).getCPU_Burst();
}